package zzu.xjc.http;


import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class HttpRequest {
    private Http.Method method;
    private String url;
    private String version;

    private final HashMap<String,String> headers = new HashMap<>();
    private HashMap<String,String> params;
    private HashMap<String,String> cookies;

    private String body;

    HttpRequest(){}
    HttpRequest(Http.Method method, String url, String version, String body) {
        this.method = method;
        this.url = url;
        this.version = version;
        this.body = body;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(this.method.toString()).append(" ")
                .append(this.url).append(" ")
                .append(this.version).append("\r\n");
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            builder.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
        }
        builder.append("\r\n").append(body).append("\r\n");
        return builder.toString();
    }

    private HashMap<String,HttpSession> sessionMap;
    private static final String JSESSIONID = "SessionID";

    void inject(HashMap<String,HttpSession> sessionMap,HttpServiceExecutor executor){
        this.sessionMap = sessionMap;
        this.executor = executor;
    }
    public HttpSession getSession(){
        HttpSession session = null;
        String sessionId = this.getCookie(JSESSIONID);
        if (sessionId == null){
            // Http请求头中没有设置session  No session is set in the Http request header
            return createEmptySession();
        }
        if ( !sessionMap.containsKey(sessionId)){
            // Server没有保存该SessionID对应的Session  Server have not the Session corresponding to this SessionID
            return createEmptySession();
        }else {
            session = sessionMap.get(sessionId);
            // 也许session刚刚过期并在执行此方法期间被删除（Session可能会被多线程并发地操作），因此我们需要判断Session是否为null
            // maybe session expired just now and be removed during this code executed (because session may be
            // operated concurrently by multi threads), so it is need to judge the session == null or not
            if(session == null){
                return createEmptySession();
            }
        }
        if (System.currentTimeMillis() > session.expireTime){
            // Session expired
            sessionMap.remove(session.SessionID);
            return createEmptySession();
        }
        return session;
    }

    private HttpSession createEmptySession(){
        String sessionID = UUID.randomUUID().toString();
        HttpSession session = new HttpSession(sessionID,HttpServer.SessionExpireMilliSeconds() + System.currentTimeMillis());
        sessionMap.put(sessionID,session);
        return session;
    }


    private HttpResponse resp;
    void setResponse(HttpResponse response){
        this.resp = response;
    }
    public void setCookie(String key,String value){
        setCookie(key, value, HttpServer.cookieExpireSeconds());
    }
    public void setCookie(String key, String value,int seconds){
        resp.setCookies().add(key + "=" + value + "; " + "Max-Age" + "=" + seconds);
    }

    private HttpServiceExecutor executor;
    public void forward(String url){
        this.url =  Http.Url.process(url);
        executor.execute(this);
    }

    void initParams(){
        params = new HashMap<>();
    }
    void initCookies(){
        cookies = new HashMap<>();
    }
    void putParam(String key, String value){
        params.put(key,value);
    }
    void putHeader(String key,String value){
        headers.put(key,value);
    }
    void putCookie(String key,String value){
        cookies.put(key,value);
    }
    public String getParam(String paramName){
        if (params == null){
            return null;
        }
        return params.get(paramName);
    }
    public boolean containsParam(String paramName){
        return params.containsKey(paramName);
    }
    public String getHeader(String headerName){
        return headers.get(headerName);
    }
    public boolean containsHeader(String headerName){
        return headers.containsKey(headerName);
    }
    public String getCookie(String cookieName){
        if (cookies == null){
            return null;
        }
        return cookies.get(cookieName);
    }
    public boolean containsCookie(String cookieName){
        return cookies.containsKey(cookieName);
    }

    void setBody(String body) {
        this.body = body;
    }
    void setMethod(Http.Method method) {
        this.method = method;
    }

    void setUrl(String url) {
        this.url = url;
    }

    void setVersion(String version) {
        this.version = version;
    }

    public Http.Method method() {
        return method;
    }
    public String url() {
        return url;
    }
    public String version() {
        return version;
    }
    public String body() {
        return body;
    }

    public static class Header{
        private Header(){}

        public static String UserAgent = "User-Agent";
        public static String Host = "Host";
        public static String Accept = "Accept";
        public static String AcceptEncoding = "Accept-Encoding";
    }

}
